"""
计算器工具

这个工具展示了如何实现一个基础的数学计算功能，
包括安全的表达式求值和错误处理。
"""

import ast
import operator
import math
from typing import Union, Any
from .base import Tool, ToolType


class CalculatorTool(Tool):
    """
    计算器工具类
    
    提供安全的数学表达式计算功能，支持基本运算和常见数学函数。
    这展示了如何实现一个具有输入验证和安全控制的工具。
    """
    
    def __init__(self):
        super().__init__(
            name="calculator",
            description="执行数学计算，支持基本运算和常见数学函数",
            tool_type=ToolType.CALCULATION
        )
        
        # 支持的运算符
        self.operators = {
            ast.Add: operator.add,
            ast.Sub: operator.sub,
            ast.Mult: operator.mul,
            ast.Div: operator.truediv,
            ast.Pow: operator.pow,
            ast.Mod: operator.mod,
            ast.USub: operator.neg,
            ast.UAdd: operator.pos,
        }
        
        # 支持的数学函数
        self.functions = {
            'abs': abs,
            'round': round,
            'max': max,
            'min': min,
            'sum': sum,
            'sqrt': math.sqrt,
            'sin': math.sin,
            'cos': math.cos,
            'tan': math.tan,
            'log': math.log,
            'log10': math.log10,
            'exp': math.exp,
            'pi': math.pi,
            'e': math.e,
        }
    
    async def execute(self, expression: str) -> Union[float, int, str]:
        """
        执行数学计算
        
        Args:
            expression: 数学表达式字符串，如 "2 + 3 * 4" 或 "sqrt(16)"
            
        Returns:
            计算结果
        """
        
        # 清理输入
        expression = expression.strip()
        if not expression:
            return "错误: 表达式不能为空"
        
        try:
            # 预处理表达式
            processed_expr = self._preprocess_expression(expression)
            
            # 解析表达式
            tree = ast.parse(processed_expr, mode='eval')
            
            # 安全求值
            result = self._safe_eval(tree.body)
            
            # 格式化结果
            return self._format_result(result)
            
        except ZeroDivisionError:
            return "错误: 除零错误"
        except ValueError as e:
            return f"错误: 数值错误 - {str(e)}"
        except Exception as e:
            return f"错误: 无法计算表达式 '{expression}' - {str(e)}"
    
    def _preprocess_expression(self, expr: str) -> str:
        """预处理表达式"""
        # 替换常见的数学符号
        replacements = {
            '×': '*',
            '÷': '/',
            '×': '*',
            '²': '**2',
            '³': '**3',
        }
        
        for old, new in replacements.items():
            expr = expr.replace(old, new)
        
        # 处理隐式乘法，如 "2(3+4)" -> "2*(3+4)"
        import re
        expr = re.sub(r'(\d+)\(', r'\1*(', expr)
        expr = re.sub(r'\)(\d+)', r')*\1', expr)
        
        return expr
    
    def _safe_eval(self, node) -> Union[int, float]:
        """安全求值AST节点"""
        if isinstance(node, ast.Constant):  # Python 3.8+
            return node.value
        elif isinstance(node, ast.Num):  # Python < 3.8
            return node.n
        elif isinstance(node, ast.BinOp):
            left = self._safe_eval(node.left)
            right = self._safe_eval(node.right)
            op = self.operators.get(type(node.op))
            if op is None:
                raise ValueError(f"不支持的运算符: {type(node.op).__name__}")
            return op(left, right)
        elif isinstance(node, ast.UnaryOp):
            operand = self._safe_eval(node.operand)
            op = self.operators.get(type(node.op))
            if op is None:
                raise ValueError(f"不支持的一元运算符: {type(node.op).__name__}")
            return op(operand)
        elif isinstance(node, ast.Call):
            func_name = node.func.id
            if func_name not in self.functions:
                raise ValueError(f"不支持的函数: {func_name}")
            
            args = [self._safe_eval(arg) for arg in node.args]
            func = self.functions[func_name]
            
            # 特殊处理某些函数
            if func_name in ['pi', 'e']:
                return func
            else:
                return func(*args)
        elif isinstance(node, ast.Name):
            # 支持的常量
            if node.id in self.functions:
                return self.functions[node.id]
            else:
                raise ValueError(f"未定义的变量: {node.id}")
        else:
            raise ValueError(f"不支持的表达式类型: {type(node).__name__}")
    
    def _format_result(self, result: Union[int, float]) -> str:
        """格式化计算结果"""
        if isinstance(result, float):
            # 检查是否为整数
            if result.is_integer():
                return str(int(result))
            else:
                # 限制小数位数
                return f"{result:.10g}"
        else:
            return str(result)
    
    def get_supported_functions(self) -> dict:
        """获取支持的函数列表"""
        return {
            name: {
                'description': self._get_function_description(name),
                'example': self._get_function_example(name)
            }
            for name in self.functions.keys()
            if not isinstance(self.functions[name], (int, float))  # 排除常量
        }
    
    def _get_function_description(self, func_name: str) -> str:
        """获取函数描述"""
        descriptions = {
            'abs': '绝对值',
            'round': '四舍五入',
            'max': '最大值',
            'min': '最小值',
            'sum': '求和',
            'sqrt': '平方根',
            'sin': '正弦函数',
            'cos': '余弦函数',
            'tan': '正切函数',
            'log': '自然对数',
            'log10': '常用对数',
            'exp': '指数函数',
        }
        return descriptions.get(func_name, '数学函数')
    
    def _get_function_example(self, func_name: str) -> str:
        """获取函数使用示例"""
        examples = {
            'abs': 'abs(-5) = 5',
            'round': 'round(3.14159, 2) = 3.14',
            'max': 'max(1, 2, 3) = 3',
            'min': 'min(1, 2, 3) = 1',
            'sqrt': 'sqrt(16) = 4',
            'sin': 'sin(pi/2) = 1',
            'cos': 'cos(0) = 1',
            'tan': 'tan(pi/4) = 1',
            'log': 'log(e) = 1',
            'log10': 'log10(100) = 2',
            'exp': 'exp(1) = e',
        }
        return examples.get(func_name, f'{func_name}(...)')


# 创建工具实例并注册到默认注册表
def register_calculator_tool():
    """注册计算器工具"""
    from .base import default_registry
    calculator = CalculatorTool()
    default_registry.register(calculator)
    return calculator

# 自动注册
register_calculator_tool()